﻿using System;
using System.Collections.Generic;
using System.Linq;
//using System.Threading;
using System.Web;
using DrillOnline.Hubs;
using Microsoft.AspNet.SignalR;
using DrillOnline.Services.Scenarios;

namespace DrillOnline.Services.Scenarios
{

    public abstract class Scenarios<T> : IScenarios, IDisposable where T : Scene, new()
    {
        public virtual string ScenariosName { get; set; }

        public virtual string SessionName { get; set; }
        public virtual string SessionKey { get; set; }

        public virtual Timeline Timeline { get; set; }

        public virtual List<T> SceneList { get; set; } //SortedSet<Scene>

        public virtual int PlayingSceneIndex { get { return Timeline.PlayingSceneIndex; } set { Timeline.PlayingSceneIndex = value; } }

        public virtual List<ActorGroup> ActorGroups { get; set; }



        public void Dispose()
        {
            Timeline.Dispose();
        }
        public Scenarios()
        {
            ActorGroups = new List<ActorGroup>();

            Timeline = new Timeline();
            Timeline.OnElapsed += Ticker_OnTicker;
            Timeline.OnStatusChange += Timeline_OnStatusChange;
        }

        void Timeline_OnStatusChange(object sender, EventArgs e)
        {
            NotifyStatusChange();
        }
        bool busy = false;
        void Ticker_OnTicker(object sender, Timeline.TickerEventArgs e)
        {
            if (busy) return;
            busy = true;
            try
            {
                NotifyTimelineUpdated(e);
                var oldpsi = PlayingSceneIndex;
                var nsl = new List<T>();
                while (PlayingSceneIndex < SceneList.Count)
                {
                    var sc = SceneList[PlayingSceneIndex];
                    if (sc.Offset > e.NewOffset) break;

                    //if (!(sc.Actors == null || sc.Actors.Length == 0))
                    //{
                    nsl.Add(sc);
                    //}
                    if (PlayingSceneIndex + 1 >= SceneList.Count)
                    {
                        Timeline.Stop();
                        break;
                    }
                    PlayingSceneIndex++;
                }

                if (oldpsi != PlayingSceneIndex)
                {
                    NotifyPlayIndexChange(oldpsi);
                }
                foreach (var g in ActorGroups)
                {
                    var gs = nsl.Where(v =>v.Groups.Contains("*") || v.Groups.Contains(g.GroupKey)).ToList();
                    if (gs.Count > 0)
                    {
                        BroadcastUpdatedScenes(g, gs);
                    }
                }

            }
            catch { }
            finally
            {
                busy = false;
            }
        }
        public virtual void NotifyTimelineUpdated(Timeline.TickerEventArgs e)
        {
            //override by subclass
        }

        public abstract void BroadcastUpdatedScenes(ActorGroup g, IList<T> sl);

        public T[] GetOldSceneList(string g, int frompidx, int max)
        {
            return SceneList.GetRange(frompidx, Math.Min(frompidx+max,PlayingSceneIndex)).Where(v=>v.Groups==null||v.Groups.Length==0|| v.Groups[0]=="*"||v.Groups.Contains(g)).ToArray();
            //return SceneList.Skip()(v => (v.Offset > fromsecoffset && v.Offset <= Timeline.PlayingOffset) && v.Groups != null && v.Groups.Contains(g))
            //    .Take(max).ToArray();
        }
        public abstract void NotifySettingChange();
        public virtual void NotifyPlayIndexChange(int oldidx)
        {
            //override by subclass
        }
        public virtual void NotifyStatusChange()
        {
            //override by subclass
        }
    }


}